package xyz.perkd.process.impl;

import org.apache.pdfbox.contentstream.operator.Operator;
import org.apache.pdfbox.cos.*;
import org.apache.pdfbox.pdfparser.PDFStreamParser;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import xyz.perkd.model.POLine;
import xyz.perkd.model.POTicket;
import xyz.perkd.util.PdfUtil;

import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public class PoParser {

    enum Stage {
        OrderType,
        OrderData,
        OrderNo,
        RevisedData,
        Seller,
        FactoryCode,
        Content,
        Labelling,
        ShipTo,
        Title,
        Style,
        Lines,
        Total,
        Notice,
        Finish
    }

    static public class Item {

        Item(String content, COSBase token) {
            this.content = content;
            this.token = token;
        }

        String content = "";
        COSBase token;
    }
//    public static POTicket parse(List<Object> tokens) {
//        System.out.println("Parsing PO");
//        POTicket ticket = new POTicket();
//
//        List<Item> strings = new ArrayList<>();
//        try {
//
//            Iterator<Object> iterator = tokens.iterator();
//            while (iterator.hasNext()) {
//                Object token = iterator.next();
//                Class<?> clazz = token.getClass();
//                if (clazz.equals(Operator.class)) {
//                } else if (clazz.equals(COSName.class)) {
//                } else if (clazz.equals(COSInteger.class)) {
//                } else if (clazz.equals(COSString.class)) {
//                    strings.add(new Item(((COSString) token).getString(), (COSString) token));
//                } else if (clazz.equals(COSFloat.class)) {
//                } else if (clazz.equals(COSArray.class)) {
//                    StringBuilder line = new StringBuilder();
//                    for (COSBase item : (COSArray) token) {
//                        if (item instanceof COSString) {
//                            line.append(((COSString) item).getString());
//                        }
//                    }
//                    strings.add(new Item(line.toString(), (COSArray) token));
//                }
//            }
//
//            for (int i = 0; i < strings.size(); i++) {
//                String trimmedStr = strings.get(i).content.trim();
//                if (trimmedStr.equals("€") || trimmedStr.equals("")) {
//                    strings.remove(i);
//                    i--;
//                    continue;
//                }
//                System.out.println(i + "\t: "  + strings.get(i).content);
//            }
//
//            int offset;
//            Stage stage = Stage.OrderType;
//            for (int i = 0; i < strings.size();) {
//                String line = strings.get(i).content;
//                COSBase token = strings.get(i).token;
////                System.out.println(i + "\t: "  + line + "stage: "+ stage);
//                switch (stage) {
//                    case OrderType: {
//                        if (line.matches(".*\\sOrder")) {
//                            String orderType = line;
//                            if (isNewLine(i + 1, strings)) { // 如果有换行，则说明类型换行了，要加回来
//                                orderType += (" " + strings.get(i+3));
//                                offset = 6;
//                            } else {
//                                offset = 3;
//                            }
//                            ticket.orderType = orderType;
//                            stage = Stage.OrderData;
//                        } else {
//                            offset = 1;
//                        }
//                        break;
//                    }
//                    case OrderData: {
//                        String[] parts = line.trim().split("\\s{2,}");
//                        System.out.println(Arrays.toString(parts));
//                        if (parts.length > 1) {
//                            ticket.orderData = parts[1];
//                        }
//                        ticket.billTo[0] = parts[0];
//                        stage = Stage.OrderNo;
//                        offset = 1;
//                        break;
//                    }
//                    case OrderNo: {
//                        String[] parts = line.trim().split("\\s{1,}");
//                        System.out.println(Arrays.toString(parts));
//                        ticket.orderNo = parts[parts.length - 1];
//                        stage = Stage.RevisedData;
//                        offset = 2;
//                        break;
//                    }
//                    case RevisedData: {
//                        String[] parts = line.trim().split("\\s{2,}");
//                        System.out.println(Arrays.toString(parts));
//                        if (parts.length > 1) {
//                            ticket.revisedData = parts[1];
//                        }
//                        ticket.billTo[1] = parts[0];
//                        stage = Stage.Seller;
//                        offset = 1;
//                        break;
//                    }
//                    case Seller: {
//                        String[] parts = line.trim().split("\\s{2,}");
//                        System.out.println(Arrays.toString(parts));
//                        if (parts.length > 1) {
//                            ticket.seller = parts[1];
//                        }
//                        ticket.billTo[2] = parts[0];
//                        stage = Stage.FactoryCode;
//                        offset = 1;
//                        break;
//                    }
//                    case FactoryCode: {
//                        String[] parts = line.trim().split("\\s{2,}");
//                        System.out.println(Arrays.toString(parts));
//                        if (parts.length > 1) {
//                            ticket.factoryCode = parts[1];
//                        }
//                        ticket.billTo[3] = parts[0];
//                        stage = Stage.Content;
//                        offset = 2;
//                        break;
//                    }
//                    case Content: {
//                        ticket.content = line.trim();
//                        stage = Stage.Labelling;
//                        offset = 1;
//                        break;
//                    }
//                    case Labelling: {
//                        ticket.labelling = line.trim();
//                        stage = Stage.ShipTo;
//                        offset = 1;
//                        break;
//                    }
//                    case ShipTo: {
//                        ticket.shipTo[0] = line.replace("€", "").trim();
//                        ticket.shipTo[1] = strings.get(i + 1).content.replace("€", "").trim();
//                        ticket.shipTo[2] = strings.get(i + 2).content.replace("€", "").trim();
//                        ticket.shipTo[3] = strings.get(i + 3).content.replace("€", "").trim();
//                        stage = Stage.Title;
//                        offset = 6;
//                        break;
//                    }
//                    case Title: {
//                        ticket.title = line.trim();
//                        stage = Stage.Style;
//                        offset = 2;
//                        break;
//                    }
//                    case Style: {
//                        ticket.style = line.trim().split("#")[1].trim();
//                        stage = Stage.Lines;
//                        offset = 10;
//                        break;
//                    }
//                    case Lines: {
//                        int cursor = i;
//                        for (int j = 0; j < 10; j++) {
//                            String ln = strings.get(cursor).content;
//                            System.out.println(j + "\t : " + ln + "\t cursor: " + cursor);
//                            if (ln != null && !ln.trim().isEmpty()) {
//                                POLine ticketLine = new POLine();
//                                ticket.lines.add(ticketLine);
//                                ticketLine.ln = ln;
//                                cursor++;
//                                ticketLine.xf = strings.get(cursor).content;
//                                ticketLine.xfToken = strings.get(cursor).token;
//                            }
//
//                            // 找到换行后继续下一个
//                            while (!isNewLine(cursor, strings)) {
//                                cursor++;
//                            }
//                            cursor += 2;
//                        }
//                        stage = Stage.Total;
//                        offset = cursor - i;
//                        break;
//                    }
//                    case Total: {
//                        ticket.orderTotal = line.trim();
//                        stage = Stage.Notice;
//                        offset = 3;
//                        break;
//                    }
//                    case Notice: {
//                        ticket.notice = line.trim();
//                        ticket.noticeToken = token;
//                        offset = 1;
//                        stage = Stage.Finish;
//                        break;
//                    }
//                    default: {
//                        offset = 1;
//                        break;
//                    }
//                }
//                i += offset;
//            }
//            System.out.println(ticket);
//
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//
//        return ticket;
//    }

    public static POTicket parse(List<Object> tokens, PDDocument document, PDPage page) {
        System.out.println("Parsing PO");
        POTicket ticket = new POTicket();

        List<Item> strings = new ArrayList<>();
        try {
            Iterator<Object> iterator = tokens.iterator();
            while (iterator.hasNext()) {
                Object token = iterator.next();
                Class<?> clazz = token.getClass();
                if (clazz.equals(Operator.class)) {
                } else if (clazz.equals(COSName.class)) {
                } else if (clazz.equals(COSInteger.class)) {
                } else if (clazz.equals(COSString.class)) {
                    strings.add(new Item( ((COSString) token).getString(), (COSString) token));
                } else if (clazz.equals(COSFloat.class)) {
                } else if (clazz.equals(COSArray.class)) {
                    StringBuilder line = new StringBuilder();
                    for (COSBase item : (COSArray) token) {
                        if (item instanceof COSString) {
                            line.append(((COSString) item).getString());
                        }
                    }
                    strings.add(new Item(line.toString(), (COSArray) token));
                } else {
                    System.out.println("Parsing no calss");
                }
            }
            ticket.orderData = "";
            String OrderDateRect = PdfUtil.getTextByArea(document, page,  new Rectangle2D.Float(70, 90, 370, 15)).trim();
            String BefOrderDateStr = "";
            String OrderDate = "";
            int index = OrderDateRect.indexOf("Order Date:");
            if (index >= 0) {
                String[] list = OrderDateRect.substring(11).split(" ");
                BefOrderDateStr = list[0].trim().replace("\u00A0", "");
                if (list.length >= 2) {
                    OrderDate=  list[list.length -1].trim().replace("\u00A0", "");
                    if (OrderDate.length() != 10) {
                        OrderDate = "";
                    }
                }
            }
            ticket.revisedData = "";
            String RevisedDateRect = PdfUtil.getTextByArea(document, page,  new Rectangle2D.Float(70, 105, 370, 15)).trim();
            String BefRevisedDateRect = "";
            String RevisedDate = "";
            index = RevisedDateRect.indexOf("Revised Date:");
            if (index >= 0) {
                String[] list = RevisedDateRect.substring(index + 13).split(" ");
                BefRevisedDateRect = list[0].trim().replace("\u00A0", "");
                if (list.length >= 2) {
                    RevisedDate =  list[list.length -1].trim().replace("\u00A0", "");
                    if (RevisedDate.length() != 10) {
                        RevisedDate = "";
                    }
                }
            }

            ticket.notice = "";
            String notesRect = PdfUtil.getTextByArea(document, page,  new Rectangle2D.Float(70, 510, 200, 15)).trim().replace("\u00A0", "");


            int OrderNoIndex = -1;
            int StyleIndex = -1;
            for (int i = 0; i < strings.size(); i++) {
                System.out.println(i + "\t: "  + strings.get(i).content);
                String trimmedStr = strings.get(i).content.trim();
                if (trimmedStr.equals("€") || trimmedStr.equals("")) {
                    strings.remove(i);
                    i--;
                    continue;
                }
                if (trimmedStr.indexOf("ORDER #") >= 0) {
                    ticket.orderNo = trimmedStr.substring(7).trim();
                    OrderNoIndex = i;
                } else if (trimmedStr.indexOf("STYLE #") >= 0) {
                    ticket.style = trimmedStr.substring(7).trim();
                    StyleIndex = i;
                } else if (trimmedStr.indexOf(BefOrderDateStr) >= 0 && !OrderDate.equals("") && trimmedStr.indexOf(OrderDate) >= 0) {
                    ticket.orderData = trimmedStr.substring(trimmedStr.indexOf(OrderDate)).trim().replace("€", "");
                } else if (trimmedStr.indexOf(BefRevisedDateRect) >= 0 && !RevisedDate.equals("") && trimmedStr.indexOf(RevisedDate) >= 0) {
                    ticket.revisedData = trimmedStr.substring(trimmedStr.indexOf(RevisedDate)).trim().replace("€", "");
                } else if (!notesRect.equals("") && trimmedStr.indexOf(notesRect) >= 0) {
                    ticket.notice = trimmedStr;
                    ticket.noticeToken = strings.get(i).token;
                }
            }

            if (ticket.orderData == "" && !OrderDate.equals("")) {
                for (int i = 0; i < strings.size(); i++) {
                    String trimmedStr = strings.get(i).content.trim();
                     if (trimmedStr.indexOf(OrderDate) >= 0) {
                        ticket.orderData = OrderDate;
                    }
                }
            }
            if (ticket.revisedData == "" &&!RevisedDate.equals("")) {
                for (int i = 0; i < strings.size(); i++) {
                    String trimmedStr = strings.get(i).content.trim();
                    if (trimmedStr.indexOf(RevisedDate) >= 0) {
                        ticket.revisedData = RevisedDate;
                    }
                }
            }


            ticket.shipTo = PdfUtil.getTextByArea(document, page,  new Rectangle2D.Float(70, 170, 205, 40)).trim().replace("\u00A0", "");

            String XFDateRect = PdfUtil.getTextByArea(document, page,  new Rectangle2D.Float(30, 285, 50, 205)).trim();
            String[] XFList = XFDateRect.split("\r\n");
            List<String> XFListReal = new ArrayList<String>();
            for (String str : XFList) {
                if (str != null && str.trim().length() == 8) {
                    XFListReal.add(str);
                }
            }
            int xfIndex = 0;
            for (int j = StyleIndex+ 1; j < strings.size();j++) {
                if (XFListReal.size() > 0) {
                    if (strings.get(j).content.indexOf(XFListReal.get(0)) >= 0) {
                        POLine ticketLine = new POLine();
                        ticket.lines.add(ticketLine);
                        ticketLine.xf = strings.get(j).content;
                        ticketLine.xfToken = strings.get(j).token;
                        ticketLine.xfReal = XFListReal.get(0);
                        ticketLine.xfRealFile = XFListReal.get(0);
                        XFListReal.remove(0);
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return ticket;
    }

    public static boolean isNewLine(int pos, List<Item> strings) {
        return strings.get(pos).content.equals("€") && strings.get(pos + 1).content.isEmpty();
    }

    public static boolean isE(int pos, List<Item> strings) {
        return strings.get(pos).content.equals("€");
    }
}
